home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / BZIP2 / 980205 / bzip / c / bzip2rec < prev   
Text File  |  1997-12-29  |  11KB  |  399 lines

  1. /*-----------------------------------------------------------*/
  2. /*--- Block recoverer program for bzip2                   ---*/
  3. /*---                                      bzip2recover.c ---*/
  4. /*-----------------------------------------------------------*/
  5.  
  6. /*--
  7.   This program is bzip2recover, a program to attempt data 
  8.   salvage from damaged files created by the accompanying
  9.   bzip2-0.1 program.
  10.  
  11.   Copyright (C) 1996, 1997 by Julian Seward.
  12.      Guildford, Surrey, UK
  13.      email: jseward@acm.org
  14.  
  15.   This program is free software; you can redistribute it and/or modify
  16.   it under the terms of the GNU General Public License as published by
  17.   the Free Software Foundation; either version 2 of the License, or
  18.   (at your option) any later version.
  19.  
  20.   This program is distributed in the hope that it will be useful,
  21.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.   GNU General Public License for more details.
  24.  
  25.   You should have received a copy of the GNU General Public License
  26.   along with this program; if not, write to the Free Software
  27.   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  
  29.   The GNU General Public License is contained in the file LICENSE.
  30. --*/
  31.  
  32.  
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <malloc.h>
  36. #include <stdlib.h>
  37. #include <strings.h>  /*-- or try string.h --*/
  38.  
  39. #define UInt32  unsigned int
  40. #define Int32   int
  41. #define UChar   unsigned char
  42. #define Char    char
  43. #define Bool    unsigned char
  44. #define True    1
  45. #define False   0
  46.  
  47.  
  48. Char inFileName[2000];
  49. Char outFileName[2000];
  50. Char progName[2000];
  51.  
  52. UInt32 bytesOut = 0;
  53. UInt32 bytesIn  = 0;
  54.  
  55.  
  56. /*---------------------------------------------------*/
  57. /*--- I/O errors                                  ---*/
  58. /*---------------------------------------------------*/
  59.  
  60. /*---------------------------------------------*/
  61. void readError ( void )
  62. {
  63.    fprintf ( stderr,
  64.              "%s: I/O error reading `%s', possible reason follows.\n",
  65.             progName, inFileName );
  66.    perror ( progName );
  67.    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
  68.              progName );
  69.    exit ( 1 );
  70. }
  71.  
  72.  
  73. /*---------------------------------------------*/
  74. void writeError ( void )
  75. {
  76.    fprintf ( stderr,
  77.              "%s: I/O error reading `%s', possible reason follows.\n",
  78.             progName, inFileName );
  79.    perror ( progName );
  80.    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
  81.              progName );
  82.    exit ( 1 );
  83. }
  84.  
  85.  
  86. /*---------------------------------------------*/
  87. void mallocFail ( Int32 n )
  88. {
  89.    fprintf ( stderr,
  90.              "%s: malloc failed on request for %d bytes.\n",
  91.             progName, n );
  92.    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
  93.              progName );
  94.    exit ( 1 );
  95. }
  96.  
  97.  
  98. /*---------------------------------------------------*/
  99. /*--- Bit stream I/O                              ---*/
  100. /*---------------------------------------------------*/
  101.  
  102. typedef
  103.    struct {
  104.       FILE*  handle;
  105.       Int32  buffer;
  106.       Int32  buffLive;
  107.       Char   mode;
  108.    }
  109.    BitStream;
  110.  
  111.  
  112. /*---------------------------------------------*/
  113. BitStream* bsOpenReadStream ( FILE* stream )
  114. {
  115.    BitStream *bs = malloc ( sizeof(BitStream) );
  116.    if (bs == NULL) mallocFail ( sizeof(BitStream) );
  117.    bs->handle = stream;
  118.    bs->buffer = 0;
  119.    bs->buffLive = 0;
  120.    bs->mode = 'r';
  121.    return bs;
  122. }
  123.  
  124.  
  125. /*---------------------------------------------*/
  126. BitStream* bsOpenWriteStream ( FILE* stream )
  127. {
  128.    BitStream *bs = malloc ( sizeof(BitStream) );
  129.    if (bs == NULL) mallocFail ( sizeof(BitStream) );
  130.    bs->handle = stream;
  131.    bs->buffer = 0;
  132.    bs->buffLive = 0;
  133.    bs->mode = 'w';
  134.    return bs;
  135. }
  136.  
  137.  
  138. /*---------------------------------------------*/
  139. void bsPutBit ( BitStream* bs, Int32 bit )
  140. {
  141.    if (bs->buffLive == 8) {
  142.       Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
  143.       if (retVal == EOF) writeError();
  144.       bytesOut++;
  145.       bs->buffLive = 1;
  146.       bs->buffer = bit & 0x1;
  147.    } else {
  148.       bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
  149.       bs->buffLive++;
  150.    };
  151. }
  152.  
  153.  
  154. /*---------------------------------------------*/
  155. /*--
  156.    Returns 0 or 1, or 2 to indicate EOF.
  157. --*/
  158. Int32 bsGetBit ( BitStream* bs )
  159. {
  160.    if (bs->buffLive > 0) {
  161.       bs->buffLive --;
  162.       return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
  163.    } else {
  164.       Int32 retVal = getc ( bs->handle );
  165.       if ( retVal == EOF ) {
  166.          if (errno != 0) readError();
  167.          return 2;
  168.       }
  169.       bs->buffLive = 7;
  170.       bs->buffer = retVal;
  171.       return ( ((bs->buffer) >> 7) & 0x1 );
  172.    }
  173. }
  174.  
  175.  
  176. /*---------------------------------------------*/
  177. void bsClose ( BitStream* bs )
  178. {
  179.    Int32 retVal;
  180.  
  181.    if ( bs->mode == 'w' ) {
  182.       while ( bs->buffLive < 8 ) {
  183.          bs->buffLive++;
  184.          bs->buffer <<= 1;
  185.       };
  186.       retVal = putc ( (UChar) (bs->buffer), bs->handle );
  187.       if (retVal == EOF) writeError();
  188.       bytesOut++;
  189.       retVal = fflush ( bs->handle );
  190.       if (retVal == EOF) writeError();
  191.    }
  192.    retVal = fclose ( bs->handle );
  193.    if (retVal == EOF)
  194.       if (bs->mode == 'w') writeError(); else readError();
  195.    free ( bs );
  196. }
  197.  
  198.  
  199. /*---------------------------------------------*/
  200. void bsPutUChar ( BitStream* bs, UChar c )
  201. {
  202.    Int32 i;
  203.    for (i = 7; i >= 0; i--)
  204.       bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
  205. }
  206.  
  207.  
  208. /*---------------------------------------------*/
  209. void bsPutUInt32 ( BitStream* bs, UInt32 c )
  210. {
  211.    Int32 i;
  212.  
  213.    for (i = 31; i >= 0; i--)
  214.       bsPutBit ( bs, (c >> i) & 0x1 );
  215. }
  216.  
  217.  
  218. /*---------------------------------------------*/
  219. Bool endsInBz2 ( Char* name )
  220. {
  221.    Int32 n = strlen ( name );
  222.    if (n <= 4) return False;
  223.    return
  224.       (name[n-4] == '.' &&
  225.        name[n-3] == 'b' &&
  226.        name[n-2] == 'z' &&
  227.        name[n-1] == '2');
  228. }
  229.  
  230.  
  231. /*---------------------------------------------------*/
  232. /*---                                             ---*/
  233. /*---------------------------------------------------*/
  234.  
  235. #define BLOCK_HEADER_HI  0x00003141UL
  236. #define BLOCK_HEADER_LO  0x59265359UL
  237.  
  238. #define BLOCK_ENDMARK_HI 0x00001772UL
  239. #define BLOCK_ENDMARK_LO 0x45385090UL
  240.  
  241. Int32 main ( Int32 argc, Char** argv )
  242. {
  243.    FILE*       inFile;
  244.    FILE*       outFile;
  245.    BitStream*  bsIn, *bsWr;
  246.    Int32       currBlock, b, wrBlock;
  247.    UInt32      bitsRead;
  248.    UInt32      bStart[20000];
  249.    UInt32      bEnd[20000];
  250.    UInt32      buffHi, buffLo, blockCRC;
  251.    Char*       p;
  252.  
  253.    strcpy ( progName, argv[0] );
  254.    inFileName[0] = outFileName[0] = 0;
  255.  
  256.    fprintf ( stderr, "bzip2recover: extracts blocks from damaged .bz2 files.\n" );
  257.  
  258.    if (argc != 2) {
  259.       fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
  260.                         progName, progName );
  261.       exit(1);
  262.    }
  263.  
  264.    strcpy ( inFileName, argv[1] );
  265.  
  266.    inFile = fopen ( inFileName, "rb" );
  267.    if (inFile == NULL) {
  268.       fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
  269.       exit(1);
  270.    }
  271.  
  272.    bsIn = bsOpenReadStream ( inFile );
  273.    fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
  274.  
  275.    bitsRead = 0;
  276.    buffHi = buffLo = 0;
  277.    currBlock = 0;
  278.    bStart[currBlock] = 0;
  279.  
  280.    while (True) {
  281.       b = bsGetBit ( bsIn );
  282.       bitsRead++;
  283.       if (b == 2) {
  284.          if (bitsRead >= bStart[currBlock] &&
  285.             (bitsRead - bStart[currBlock]) >= 40) {
  286.             bEnd[currBlock] = bitsRead-1;
  287.             if (currBlock > 0)
  288.                fprintf ( stderr, "   block %d runs from %d to %d (incomplete)\n",
  289.                          currBlock,  bStart[currBlock], bEnd[currBlock] );
  290.          } else
  291.             currBlock--;
  292.          break;
  293.       }
  294.       buffHi = (buffHi << 1) | (buffLo >> 31);
  295.       buffLo = (buffLo << 1) | (b & 1);
  296.       if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 
  297.              && buffLo == BLOCK_HEADER_LO)
  298.            || 
  299.            ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 
  300.              && buffLo == BLOCK_ENDMARK_LO)
  301.          ) {
  302.          if (bitsRead > 49)
  303.             bEnd[currBlock] = bitsRead-49; else
  304.             bEnd[currBlock] = 0;
  305.          if (currBlock > 0)
  306.             fprintf ( stderr, "   block %d runs from %d to %d\n",
  307.                       currBlock,  bStart[currBlock], bEnd[currBlock] );
  308.          currBlock++;
  309.          bStart[currBlock] = bitsRead;
  310.       }
  311.    }
  312.  
  313.    bsClose ( bsIn );
  314.  
  315.    /*-- identified blocks run from 1 to currBlock inclusive. --*/
  316.  
  317.    if (currBlock < 1) {
  318.       fprintf ( stderr,
  319.                 "%s: sorry, I couldn't find any block boundaries.\n",
  320.                 progName );
  321.       exit(1);
  322.    };
  323.  
  324.    fprintf ( stderr, "%s: splitting into blocks\n", progName );
  325.  
  326.    inFile = fopen ( inFileName, "rb" );
  327.    if (inFile == NULL) {
  328.       fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
  329.       exit(1);
  330.    }
  331.    bsIn = bsOpenReadStream ( inFile );
  332.  
  333.    /*-- placate gcc's dataflow analyser --*/
  334.    blockCRC = 0; bsWr = 0;
  335.  
  336.    bitsRead = 0;
  337.    outFile = NULL;
  338.    wrBlock = 1;
  339.    while (True) {
  340.       b = bsGetBit(bsIn);
  341.       if (b == 2) break;
  342.       buffHi = (buffHi << 1) | (buffLo >> 31);
  343.       buffLo = (buffLo << 1) | (b & 1);
  344.       if (bitsRead == 47+bStart[wrBlock]) 
  345.          blockCRC = (buffHi << 16) | (buffLo >> 16);
  346.  
  347.       if (outFile != NULL && bitsRead >= bStart[wrBlock]
  348.                           && bitsRead <= bEnd[wrBlock]) {
  349.          bsPutBit ( bsWr, b );
  350.       }
  351.  
  352.       bitsRead++;
  353.  
  354.       if (bitsRead == bEnd[wrBlock]+1) {
  355.          if (outFile != NULL) {
  356.             bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
  357.             bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
  358.             bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
  359.             bsPutUInt32 ( bsWr, blockCRC );
  360.             bsClose ( bsWr );
  361.          }
  362.          if (wrBlock >= currBlock) break;
  363.          wrBlock++;
  364.       } else
  365.       if (bitsRead == bStart[wrBlock]) {
  366.          outFileName[0] = 0;
  367.          sprintf ( outFileName, "rec%4d", wrBlock );
  368.          for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0';
  369.          strcat ( outFileName, inFileName );
  370.          if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
  371.  
  372.          fprintf ( stderr, "   writing block %d to `%s' ...\n",
  373.                            wrBlock, outFileName );
  374.  
  375.          outFile = fopen ( outFileName, "wb" );
  376.          if (outFile == NULL) {
  377.             fprintf ( stderr, "%s: can't write `%s'\n",
  378.                       progName, outFileName );
  379.             exit(1);
  380.          }
  381.          bsWr = bsOpenWriteStream ( outFile );
  382.          bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' );
  383.          bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' );
  384.          bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
  385.          bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
  386.          bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
  387.       }
  388.    }
  389.  
  390.    fprintf ( stderr, "%s: finished\n", progName );
  391.    return 0;
  392. }
  393.  
  394.  
  395.  
  396. /*-----------------------------------------------------------*/
  397. /*--- end                                  bzip2recover.c ---*/
  398. /*-----------------------------------------------------------*/
  399.